#ifndef _GL_SCENE_H_
#define _GL_SCENE_H_

#define IN
#define OUT

#include "glMesh.h"
#include "XobjIO.h"
#include "glWorld.cuh"

#include "../cuCommon/cuTypes.h"
#include "../cuCommon/cuBuffer.h"
#include "../rtCommon/Axis.h"
#include "../rtCommon/Execution.h"
#include "../rtCommon/Box.h"
#include "../rtCommon/SpatialTree.h"

#include "../glCommon/glRender.h"

//#include "../RadixSort/IceRevisitedRadix.h"

class CglWorld : public CglMesh
{
protected:
	uint32     m_nMesh;
	CglMesh *  m_pMesh;

	//////////////////////////////////////////////////////////////////////////
	/// buffer that holds per element mesh ID
	//////////////////////////////////////////////////////////////////////////

	ui_Buffer  posIdxSwizzled;
	ui_Buffer  posMeshId;
	ui_Buffer  posIdxMeshId;

	//////////////////////////////////////////////////////////////////////////
	/// buffers that hold offsets to individual mesh information
	//////////////////////////////////////////////////////////////////////////

	sf4Buffer   b_matrix;

	sf4Buffer   b_diffuse;
	sf4Buffer   b_ambient;
	sf4Buffer   b_specular;
	sf4Buffer   b_emission;
	sf_Buffer   b_shininess;

	ui_Buffer  posO;     // position offset buffer
	ui_Buffer  clrO;     //
	ui_Buffer  nmlO;     // 
	ui_Buffer  tntO;     // 
	ui_Buffer  bntO;     // 
	ui_Buffer  uv_O;     // 

	ui_Buffer  posIdxO;  //
	ui_Buffer  clrIdxO;  //
	ui_Buffer  uv_IdxO;  //

	//////////////////////////////////////////////////////////////////////////
	/// buffers that hold individual mesh sizes
	//////////////////////////////////////////////////////////////////////////

	ui_Buffer  posC;
	ui_Buffer  clrC;
	ui_Buffer  nmlC;
	ui_Buffer  tntC;
	ui_Buffer  bntC;
	ui_Buffer  uv_C;

	ui_Buffer  posIdxC;
	ui_Buffer  clrIdxC;
	ui_Buffer  uv_IdxC;

	void     Null();

public:
	CglWorld();
	virtual ~CglWorld();

	void     Create(CXobjIO ** ppXobj, uint32 nXobj);
	void     Release();

	void     Memcpy(uint8 dirFlags, uint8 cpyFlags);

	//////////////////////////////////////////////////////////////////////////
	/// VBO Update routine 
	//////////////////////////////////////////////////////////////////////////
	void     Update(uint8 uFlags);

	void     Swap();

	uint32   nMesh() { return m_nMesh; }
	CglMesh *pMesh() { return m_pMesh; }

	//////////////////////////////////////////////////////////////////////////
	/// KD Tree construction stages:
	//////////////////////////////////////////////////////////////////////////
protected:
	CSpatialTree   m_tree;

public:
	//////////////////////////////////////////////////////////////////////////
	/// 1. Transform to World Space
	//////////////////////////////////////////////////////////////////////////
	void     TransformWS    (uint8 exeFlags);

	//////////////////////////////////////////////////////////////////////////
	/// 2. Compute Axis Aligned Bounding Box for resulting scene
	//////////////////////////////////////////////////////////////////////////
	void     SceneAABB      (uint8 exeFlags);

	//////////////////////////////////////////////////////////////////////////
	/// 3. Compute Individual Axis Aligned Bounding Boxes for each primitive
	//////////////////////////////////////////////////////////////////////////
	void     PrimitiveAABB  (uint8 exeFlags);

	//////////////////////////////////////////////////////////////////////////
	/// 4. Compute Min Max Histogram and Pyramid for KD Tree binning
	//////////////////////////////////////////////////////////////////////////
	void     Histogram      (uint8 exeFlags);

	//////////////////////////////////////////////////////////////////////////
	/// 5 Use Scene Vertices's as split position candidates
	//////////////////////////////////////////////////////////////////////////
	void     SortSplitCandidates(uint8 exeFlags);

	//////////////////////////////////////////////////////////////////////////
	/// 6 Build KdTree
	//////////////////////////////////////////////////////////////////////////
	void     KdTree(uint8 exeFlags);

	//////////////////////////////////////////////////////////////////////////
	/// 7 Build BVHTree
	//////////////////////////////////////////////////////////////////////////
	void     BVHTree(uint8 exeFlags);

	//////////////////////////////////////////////////////////////////////////
	/// 8 Build OctTree
	//////////////////////////////////////////////////////////////////////////
	void     OctTree(uint8 exeFlags);

	//////////////////////////////////////////////////////////////////////////
	/// Get Data methods
	//////////////////////////////////////////////////////////////////////////
	sf2Buffer * KdTree();

	sf4Buffer * Position();
	si_Buffer * Face();

	//////////////////////////////////////////////////////////////////////////
	/// Trace methods
	//////////////////////////////////////////////////////////////////////////
	void KdTrace(IN  sf4Buffer & rayO, 
		           IN  sf4Buffer & rayD, 
							 OUT sf_Buffer & tminBuffer, 
							 OUT si2Buffer & idBuffer, 
							 OUT uc4Buffer & rgba8);

	void KdTrace(IN  float3    & orig,
							 IN  float3    & dir, 
							 IN  int         iRay,
							 OUT sf_Buffer & tminBuffer, 
							 OUT si2Buffer & idBuffer, 
							 OUT uc4Buffer & rgba8);

	void BVHTrace(IN  sf4Buffer & rayO, 
		            IN  sf4Buffer & rayD, 
							  OUT sf_Buffer & tminBuffer, 
							  OUT si2Buffer & idBuffer, 
							  OUT uc4Buffer & rgba8);

	void BVHTrace(IN  float3    & orig,
							  IN  float3    & dir, 
							  IN  int         iRay,
							  OUT sf_Buffer & tminBuffer, 
							  OUT si2Buffer & idBuffer, 
							  OUT uc4Buffer & rgba8);

	//////////////////////////////////////////////////////////////////////////
	/// Render methods
	//////////////////////////////////////////////////////////////////////////
	void RenderKdTree(int maxLevel, bool empty);
	void RenderKdTreeLeaf(int maxLevel, bool empty);
	void RenderBVHTree(int maxLevel, bool empty);
	void RenderBVHTreeLeaf(int maxLevel, bool empty);
	void RenderKdTreeRayTrace(const float3 & orig, const float3 & dir, int maxLevel, bool empty);
	void RenderBVHTreeRayTrace(const float3 & orig, const float3 & dir, int maxLevel, bool empty);
};

#endif